﻿module FSChart.Builder

open System.Drawing

// helpers & aliases

let konst a b = a
let setAs = konst

let on  = true
let off = false

// chart & contents constructors

module C =
    
    let create c = ChartDef.Create c
    let contents cs (c : ChartDef) = c.SetContents cs
    
    let plot a ss = Plot(a, ss)
    
    let stackV ds ls    = StackV (ds, ls)
    let stackH ds ls    = StackH (ds, ls)
    let splitV h1 l1 l2 = StackV ([h1; 1.0 - h1], [l1; l2])
    let splitH w1 l1 l2 = StackH ([w1; 1.0 - w1], [l1; l2])
    let column ls       = StackV (ls |> List.map (konst 1.0), ls)
    let row    ls       = StackH (ls |> List.map (konst 1.0), ls)
    
    let margin  l t r b layout = Margin( l  , t  , r  , b  , layout)
    let marginU u       layout = Margin( u  , u  , u  , u  , layout)
    let marginL l       layout = Margin( l  , 0.0, 0.0, 0.0, layout)
    let marginT t       layout = Margin( 0.0, t  , 0.0, 0.0, layout)
    let marginR r       layout = Margin( 0.0, 0.0, r  , 0.0, layout)
    let marginB b       layout = Margin( 0.0, 0.0, 0.0, b  , layout)
    
    let single areaDef series =
        create <| Plot ( areaDef, series )
    
    let lattice marginO marginI contents =
        
        let ( outerL, outerT, outerR, outerB ) = marginO
        let ( innerL, innerT, innerR, innerB ) = marginI
        
        create <|
        margin outerL outerT outerR outerB
            ( column [ for r in contents ->
                        row [ for (a, s) in r ->
                                margin innerL innerT innerR innerB
                                    (plot a s) ] ] )

// area default values

let areaD = AreaDef.Create XDate
let areaF = AreaDef.Create XFloat
let areaS = AreaDef.Create XString

// area transforms

let typeX   tx (area : AreaDef) = area.SetTypeX   tx
let axisX   f  (area : AreaDef) = area.SetAxisX   f
let axisY   f  (area : AreaDef) = area.SetAxisY   f
let axisY2  f  (area : AreaDef) = area.SetAxisY2  f
let legend  f  (area : AreaDef) = area.SetLegend  f
let alignTo a  (area : AreaDef) = area.SetAlignTo a
let style3D f  (area : AreaDef) = area.SetStyle3D f

let alignH  a = alignTo (AreaAlignment.Horizontal a)
let alignV  a = alignTo (AreaAlignment.Vertical   a)

// 3D style transforms

let view    v (s : Style3D) = s.SetView    v
let depth   d (s : Style3D) = s.SetDepth   d
let wall    w (s : Style3D) = s.SetWall    w
let realism r (s : Style3D) = s.SetRealism r

// axis default value

let axis = AxisDef.Default

// axis transforms

let grid     f (axis : AxisDef) = axis.SetGrid     f
let scale    s (axis : AxisDef) = axis.SetScale    s
let crossing c (axis : AxisDef) = axis.SetCrossing c
let ticks    t (axis : AxisDef) = axis.SetTicks    t
let margin   m (axis : AxisDef) = axis.SetMargin   m
let reversed r (axis : AxisDef) = axis.SetReversed r

let linear  s = scale ( Linear(s, true ) )
let linearI s = scale ( Linear(s, false) )
let loglog  s = scale ( LogLog s )
let loglin  s = scale ( LogLin s )
let range   s = scale ( Range  s )
let timeX   s = scale ( TimeX  s )

let crossAtMin m = crossing ( CrossAtMin m )
let crossAtMax m = crossing ( CrossAtMax m )
let crossAt  v m = crossing ( CrossAtVal(m, v) )

// series default values

let line          = SeriesDef.Create  Line
let fastLine      = SeriesDef.Create  FastLine
let stepLine      = SeriesDef.Create  StepLine
let scatter       = SeriesDef.Create  Scatter
let fastPoint     = SeriesDef.Create  FastPoint
let ohlc          = SeriesDef.Create  OHLC
let filledArea    = SeriesDef.Create  FilledArea
let stackedArea   = SeriesDef.Create  StackedArea
let band          = SeriesDef.Create  Band
let pie           = SeriesDef.Create  Pie
let polar         = SeriesDef.Create  Polar
let radar         = SeriesDef.Create  Radar
let radarArea     = SeriesDef.Create  RadarArea

// series constructors

let bar         w = SeriesDef.Create (Bar         w)
let barH        w = SeriesDef.Create (BarH        w)
let stackedBar  w = SeriesDef.Create (StackedBar  w)
let stackedBarH w = SeriesDef.Create (StackedBarH w)
let candles     w = SeriesDef.Create (Candlestick w)

let spline      t = SeriesDef.Create (Spline      t)
let splineArea  t = SeriesDef.Create (SplineArea  t)
let splineBand  t = SeriesDef.Create (SplineBand  t)

// series transforms

let stype  t (series : SeriesDef) = series.SetType   t
let marker f (series : SeriesDef) = series.SetMarker f
let onAxisY1 (series : SeriesDef) = series.SetAxisY  Primary
let onAxisY2 (series : SeriesDef) = series.SetAxisY  Secondary

// marker transforms

let shape  s (marker : MarkerDef) = marker.SetShape  s
let size   s (marker : MarkerDef) = marker.SetSize   s
let step   s (marker : MarkerDef) = marker.SetStep   s

let triangle = shape Triangle
let square   = shape Square
let diamond  = shape Diamond
let circle   = shape Circle
let cross    = shape Cross
let star     = shape Star

// title transforms

let horizontal h (t : TitleDef) = t.SetHorizontal h

// label transforms

let angle a (l : LabelDef) = l.SetAngle a

// statically resolved polymorphic transforms

let inline title      f (e : ^e) = (^e : (member SetTitle      : (TitleDef -> TitleDef) -> ^e) (e, f))
let inline labels     f (e : ^e) = (^e : (member SetLabels     : (LabelDef -> LabelDef) -> ^e) (e, f))

let inline text       t (e : ^e) = (^e : (member SetText       : string     -> ^e) (e, t))
let inline font       f (e : ^e) = (^e : (member SetFont       : FontDef    -> ^e) (e, f))
let inline autofit    a (e : ^e) = (^e : (member SetAutoFit    : bool       -> ^e) (e, a))
let inline format     f (e : ^e) = (^e : (member SetFormat     : string     -> ^e) (e, f))
let inline color      c (e : ^e) = (^e : (member SetColor      : Color      -> ^e) (e, c))
let inline location   l (e : ^e) = (^e : (member SetLocation   : Location   -> ^e) (e, l))
let inline alignment  a (e : ^e) = (^e : (member SetAlignment  : Alignment  -> ^e) (e, a))
let inline inside_    i (e : ^e) = (^e : (member SetInside     : bool       -> ^e) (e, i))
let inline pen        p (e : ^e) = (^e : (member SetPen        : LineDef    -> ^e) (e, p))
let inline border_    b (e : ^e) = (^e : (member SetBorder     : LineDef    -> ^e) (e, b))
let inline background b (e : ^e) = (^e : (member SetBackground : Background -> ^e) (e, b))

let inline top     e = location  Top    e
let inline bottom  e = location  Bottom e
let inline left    e = location  Left   e
let inline right   e = location  Right  e

let inline near    e = alignment Near   e
let inline center  e = alignment Center e
let inline far     e = alignment Far    e

let inline inside  e = inside_   true   e
let inline outside e = inside_   false  e

let inline solid      c w e = pen    (Solid     , c, w) e
let inline dot        c w e = pen    (Dot       , c, w) e
let inline dash       c w e = pen    (Dash      , c, w) e
let inline dashDot    c w e = pen    (DashDot   , c, w) e
let inline dashDotDot c w e = pen    (DashDotDot, c, w) e

let inline border     c w e = border_(Solid     , c, w) e

let inline backColor c e =
    background (Uniform c) e

let inline gradient c1 c2 e =
    background (Gradient(c1, c2)) e

let inline transparent e = backColor Color.Transparent e

// color aliases

let alpha a (c : Color) = Color.FromArgb(a, int c.R, int c.G, int c.B)

let black          = Color.Black
let gray           = Color.Gray
let darkGray       = Color.DarkGray
let lightGray      = Color.LightGray
let gainsboro      = Color.Gainsboro
let white          = Color.White
let whiteSmoke     = Color.WhiteSmoke
let floralWhite    = Color.FloralWhite
let antiqueWhite   = Color.AntiqueWhite
let red            = Color.Red
let darkRed        = Color.DarkRed
let green          = Color.Green
let darkGreen      = Color.DarkGreen
let lightGreen     = Color.LightGreen
let seaGreen       = Color.SeaGreen
let darkSeaGreen   = Color.DarkSeaGreen
let lightSeaGreen  = Color.LightSeaGreen
let mintCream      = Color.MintCream
let blue           = Color.Blue
let darkBlue       = Color.DarkBlue
let lightBlue      = Color.LightBlue
let skyBlue        = Color.SkyBlue
let deepSkyBlue    = Color.DeepSkyBlue
let lightSkyBlue   = Color.LightSkyBlue
let steelBlue      = Color.SteelBlue
let lightSteelBlue = Color.LightSteelBlue
let aliceBlue      = Color.AliceBlue
let azure          = Color.Azure
let cyan           = Color.Cyan
let darkCyan       = Color.DarkCyan
let lightCyan      = Color.LightCyan
let magenta        = Color.Magenta
let darkMagenta    = Color.DarkMagenta
let indigo         = Color.Indigo
let blueViolet     = Color.BlueViolet
let yellow         = Color.Yellow
let lightYellow    = Color.LightYellow
let ivory          = Color.Ivory
let gold           = Color.Gold
let orange         = Color.Orange
let orangeRed      = Color.OrangeRed
let darkOrange     = Color.DarkOrange

// font helpers

let inline arialR sz = font ("Arial", float32 sz, FontStyle.Regular)
let inline arialB sz = font ("Arial", float32 sz, FontStyle.Bold   )

